package com.huawei.codearts.service;

import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
import com.huawei.codearts.esmapper.MemberMapper;
import com.huawei.codearts.model.Member;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.data.elasticsearch.core.script.Script;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Service
public class EsService {

    @Autowired
    private ElasticsearchOperations elasticsearchOperations;

    private final MemberMapper memberMapper;

    @Autowired
    public EsService(MemberMapper memberMapper) {
        this.memberMapper = memberMapper;
    }

    public Object asve(Member member) {
        //直接将数据保存到es中，索引名称为aidite_member_demo，在member对象中设置的
        //通过kibana进行查询GET /aidite_member_demo/_search
        Member data = memberMapper.save(member);
        System.out.println("save = " + data);
        return data;
    }

    public Object del(String id) {
        memberMapper.deleteById(id);
        return "";
    }

    public Object del(Member member) {
        memberMapper.delete(member);
        return "";
    }

    public List<Member> find() {
        // 查询全部数据
        Iterable<Member> all = memberMapper.findAll();
        List<Member> list = new ArrayList<>();
        for (Member mamber : all) {
            list.add(mamber);
        }

        // 使用 Collections.sort方法按照用户的ID进行排序
//        Collections.sort(list, Comparator.comparing(Member::getId));

        // 使用自定义比较器按照某字段进行排序
        Collections.sort(list, new Comparator<Member>() {
            @Override
            public int compare(Member user1, Member user2) {
                // 假设是字符串类型
                return user1.getName().compareTo(user2.getName());
            }
        });

        // 使用流（Stream）按照用户的ID进行排序
//        List<Member> sortedList = list.stream()
//                .sorted(Comparator.comparing(Member::getId))
//                .collect(Collectors.toList());
        // 现在list中的用户已按照ID升序排列
        for (Member item : list) {
            System.out.println("member = " + item);
        }

        return list;
    }

    public Optional<Member> findById(String id) {
        // 注意这里的id是字符串类型，然后userMapper中继承的id也必须是String类型
        Optional<Member> byId = memberMapper.findById(id);
        System.out.println("byId = " + byId);
        return byId;
    }

    public Iterable<Member> findByIdAll(ArrayList<String> ids) {
        //通过 ids（集合）进行查询对应的user集合对象
        Iterable<Member> allById = memberMapper.findAllById(ids);
        for (Member item : allById) {
            System.out.println("member = " + item);
        }
        return allById;
    }

    public Map<String, Long> findCount() {
        long count = memberMapper.count();
        System.out.println("count 数 " + count);
        return Map.of("count", count);
    }

    public Map<String, Boolean> existsById(String id) {
        boolean exists = memberMapper.existsById(id);
        System.out.println("id是否存在： " + exists);
        return Map.of("exists", exists);
    }

    public Object findByLike() {
        // 模糊查询，会通过命名规范进行一个查询
        List<Member> countryData = memberMapper.findByCountryLikeIgnoreCaseOrderByCreatetimeDesc("中国");
        System.out.println("country = " + countryData);

        Page<Member> page = memberMapper.findByName("a诗经取名女孩", PageRequest.of(0, 10));
        System.out.println("page = " + page.getContent());

        Member zhangList = memberMapper.findByUser("1172383785@qq.com");
        System.out.println("user = " + zhangList);

        List<Member> country = memberMapper.findByCountry("中国");
        System.out.println("country = " + country);

        return countryData;
    }

    public List<Member> findByDescription() {
        List<Member> data = memberMapper.findByDescription("机构");
        System.out.println("description = " + data);
        return data;
    }

    public Object search() throws IOException {

        int page = 1;
        int pageSize = 10;
        PageRequest pageable = PageRequest.of((page - 1) * pageSize, pageSize);

        // api 接口模版查询
        NativeQuery nativeQuery = NativeQuery.builder()
                .withQuery(q -> q.match(m -> m.field("name").query("a诗经取名女孩")))
                .withQuery(q -> q.match(m -> m.field("user").query("1172383785@qq.com")))
                .withAggregation("group_country", Aggregation.of(a -> a
                        .terms(ta -> ta.field("country").size(10))))
                .withPageable(pageable)
                .build();
        SearchHits<Member> searchHits = elasticsearchOperations.search(nativeQuery, Member.class);
        System.out.println("searchHits...nativeQuery..." + searchHits);
        System.out.println("searchHits...nativeQuery..." + searchHits.getTotalHits());
        System.out.println("searchHits...nativeQuery..." + searchHits.getSearchHits());


        // 根据json字符串查询
//        Query stringQuery = new StringQuery("""
//                    {
//                        "match": {
//                            "name": {
//                                "query": "bb诗经取名女孩"
//                            }
//                        }
//                    }
//                """);
        Query stringQuery = new StringQuery(""" 
                    {
                       "bool":{
                         "must":[
                           {
                             "match": {
                                 "user": {
                                     "query": "2272383785@qq.com"
                                 }
                             }
                           }
                         ]
                       }
                     }
                """);
        stringQuery.setPageable(pageable);
        SearchHits<Member> searchHits2 = elasticsearchOperations.search(stringQuery, Member.class);
        System.out.println("searchHits2...stringQuery..."+searchHits2);
        System.out.println("searchHits2...stringQuery..."+searchHits2.getTotalHits());
        System.out.println("searchHits2...stringQuery..."+searchHits2.getSearchHits());


        // script查询
        elasticsearchOperations.putScript(
                Script.builder()
                        .withId("member-description")
                        .withLanguage("mustache")
                        .withSource("""                              
                            {
                                "query": {
                                  "bool": {
                                    "must": [
                                      {
                                        "match": {
                                          "description": "{{description}}"
                                        }
                                      }
                                    ]
                                  }
                                },
                                "from": "{{from}}",
                                "size": "{{size}}",
                                "aggregations": {
                                    "group_country": {
                                      "terms": {
                                        "field": "country"
                                      },
                                      "aggregations": {
                                        "group_timestamp": {
                                          "date_histogram": {
                                            "field": "timestamp",
                                            "interval": "month",
                                            "format": "yyyy-MM-dd"
                                          }
                                        }
                                      }
                                    }
                                  }
                            }
                        """).build()
        );
        var scriptQuery = SearchTemplateQuery.builder()
                .withId("member-description")
                .withParams(
                        Map.of(
                                "description", "机构",
                                "from", pageable.getOffset(),
                                "size", pageable.getPageSize()
                        )
                )
                .build();
        SearchHits<Member> searchHits3 = elasticsearchOperations.search(scriptQuery, Member.class);

//        return SearchHitSupport.searchPageFor(searchHits3, pageable);
        System.out.println("searchHits3...scriptQuery..."+searchHits3);
        System.out.println("searchHits3...scriptQuery..."+SearchHitSupport.searchPageFor(searchHits3, pageable));
        System.out.println("searchHits3...scriptQuery..."+searchHits3.getSearchHits());
        System.out.println("searchHits3...scriptQuery..."+SearchHitSupport.searchPageFor(searchHits3, pageable).getSearchHits());
        System.out.println("searchHits3...scriptQuery..."+SearchHitSupport.searchPageFor(searchHits3, pageable).getSearchHits().getSearchHits());
        System.out.println("searchHits3...aggregations..."+searchHits3.getAggregations());

        // 组装数据
        ArrayList<Object> dataList = new ArrayList<>();
        for (SearchHit<Member> item : searchHits3.getSearchHits()) {
            dataList.add(item.getContent());
        }
        Map<String, Object> dataMap = new ConcurrentHashMap<>();
        long totalHits = searchHits3.getTotalHits();
        dataMap.put("page", page);
        dataMap.put("pageSize", pageSize);
        dataMap.put("total", totalHits);
        dataMap.put("data", dataList);
        System.out.println("dataMap..."+dataMap);

        AggregationsContainer<?> buckets = searchHits3.getAggregations();
        System.out.println("buckets..."+buckets);
        System.out.println("buckets..."+searchHits3);

        return dataMap;
    }

}